import { patch } from './vdom/patch.js'
import Watcher from './observe/watcher.js'

export function mountComponent(vm, el) {
  // 上一步模板编译解析生成了render函数
  // 下一步就是执行vm._render()方法 调用生成的render函数 生成虚拟dom
  // 最后使用vm._update()方法把虚拟dom渲染到页面

  // 真实的el选项赋值给实例的$el属性 为之后虚拟dom产生的新的dom替换老的dom做铺垫
  vm.$el = el

  callHook(vm, 'beforeMount') //初始渲染之前

  // 注册一个渲染 watcher 执行 vm._update(vm._render()) 方法渲染视图
  let updateComponent = () => {
    console.log('刷新页面')
    // 实例挂载
    // vm._render() => vdom
    // vm._update => patch (vdom => 真实dom)
    vm._update(vm._render())
  }

  new Watcher(
    vm,
    updateComponent,
    () => {
      callHook(vm, 'beforeUpdate') //更新之前
    },
    true
  )

  callHook(vm, 'mounted') //渲染完成之后
}

export function lifecycleMixin(Vue) {
  // vm._update => patch (vdom => 真实dom)
  Vue.prototype._update = function (vnode) {
    const vm = this
    const prevVnode = vm._vnode // 保留上一次的vnode
    vm._vnode = vnode

    if (!prevVnode) {
      // 将 patch 后的节点重新赋值给 vm.$el, 表示上一个节点
      vm.$el = patch(vm.$el, vnode)
    } else {
      // // 更新时把上次的vnode和这次更新的vnode穿进去 进行diff算法
      vm.$el = patch(prevVnode, vnode)
    }
  }
}

export function callHook(vm, hook) {
  // 依次执行生命周期对应的方法
  const handlers = vm.$options[hook]
  if (handlers) {
    for (let i = 0; i < handlers.length; i++) {
      handlers[i].call(vm) //生命周期里面的this指向当前实例
    }
  }
}
